#include "CustomPlayer.h"

#include "FieldCoord.h"
#include "EdgeCoord.h"
#include "VertexCoord.h"

#include "FieldInformation.h"
#include "EdgeInformation.h"
#include "VertexInformation.h"
#include "SettlementInformation.h"
#include "AttackResultInformation.h"

#include "ResourcePackage.h"

#include "Player.h"

#include "AttackFailedException.h"
#include "BuildingFailedException.h"
#include "DevelopmentFailedException.h"
#include "TrainingFailedException.h"
#include "NotEnoughResourcesException.h"
#include "CoordOutOfBoundsException.h"
#include "IllFormedCoordException.h"
#include "NotReachableException.h"
#include "NotVisibleException.h"

#include <cmath>

using namespace std;
using namespace Custom;

bool operator<(const FieldCoord& a,const FieldCoord& b)
{
	return (a.x < b.x || (a.x==b.x && a.y<b.y));
}

CustomPlayer::CustomPlayer( ): Player("Custom Player") {}

void CustomPlayer::act( )
{
	try {
	++steps;
	myTowns = settlements();
	vector<VertexCoord> freeVertices = atDistanceFromMyTowns();
	
	double bestValue = 0.0;
	VertexCoord bestVertex;
	for(auto it = freeVertices.begin(); it != freeVertices.end(); ++it)
			if (value(*it) > bestValue) {
				bestValue = value(*it);
				bestVertex = *it;
			}
	buildRoads
	
	for(unsigned i=0;i<myTowns.size();++i) {
//		buildRoads(myTowns[i]);
		
		if (developmentPrice() <= resources() && myTowns[i].type!="big_city") 
			developSettlement(myTowns[i].coords);
	}
	}
	catch (...) {}
}

void CustomPlayer::init( )
{	
	steps = 0;
}

vector<VertexCoord> CustomPlayer::atDistanceFromMyTowns(unsigned d)
{
	vector<VertexCoord> towns = allTowns();
	vector<VertexCoord> res;
	
	for (unsigned i=0;i<maxFieldCoord().x;++i)
		for (unsigned j=0;j<maxFieldCoord().y;++j) {
			VertexCoord v {i, j, VertexCoord::TOP_LEFT};
			
			unsigned minDist = max(maxFieldCoord().x, maxFieldCoord().y);
			for(auto it = myTowns.begin(); it != myTowns.end() ;++it)
				if (distance(v, it->coords) < minDist)
					minDist = distance(v, it->coords);
					
			unsigned minDistFromAll = max(maxFieldCoord().x, maxFieldCoord().y);
			for(auto it = towns.begin(); it != towns.end() ;++it)
				if (distance(v, *it) < minDistFromAll)
					minDistFromAll = distance(v, *it);
					
			if (minDist == d && minDistFromAll >= d)
				res.push_back(v);
		}
	return res;
}

vector<VertexCoord> CustomPlayer::atDistanceFrom(const VertexCoord& vertex, unsigned d)
{
	VertexCoord v = vertex.normalize();
	vector<VertexCoord> res;
	for(unsigned i = 1; i <= d; ++i) {
		VertexCoord w1 {v.x+i, v.y+d-i, v.z};
		VertexCoord w2 {v.x-i, v.y+d-i, v.z};
		VertexCoord w3 {v.x+i, v.y-d+i, v.z};
		VertexCoord w4 {v.x-i, v.y-d+i, v.z};
		res.push_back(w1);
		res.push_back(w2);
		res.push_back(w3);
		res.push_back(w4);
	}
	return res;
}

double CustomPlayer::value(const VertexCoord& vertex)
{
	vector<FieldCoord> fields = vertex.adjacentFields();
	double sum = 0.0;
	for(auto it = fields.begin(); it != fields.end(); ++it)
		sum += field(*it).prob;
	return sum;
}

unsigned CustomPlayer::distance(const VertexCoord& vertex1, const VertexCoord& vertex2)
{
	VertexCoord v1 = vertex1.normalize();
	VertexCoord v2 = vertex2.normalize();
	return abs(v1.x - v2.x) + abs(v1.y - v2.y);
}

vector<VertexCoord> CustomPlayer::allTowns ()
{
	vector<VertexCoord> res;
	
	for (unsigned i=0;i<maxFieldCoord().x;++i)
		for (unsigned j=0;j<maxFieldCoord().y;++j) {
			VertexCoord v {i,j,VertexCoord::TOP_LEFT};
			if (!vertex(v).empty)
				res.push_back(v);
		}
	
	return res;
}